Download IPython notebook here. Binder badge.

GitHub issues by-label

GeometryPlot

[1]:
import sisl
import sisl.viz.plotly
import numpy as np

First of all, we will create a geometry to work with

[2]:
geom = sisl.geom.graphene_nanoribbon(9)

GeometryPlot allows you to quickly visualize a geometry. You can create a GeometryPlot out of a geometry very easily:

[3]:
# GeometryPlot is the default plot of a geometry, so one can just do
plot = geom.plot()

Now let’s see what we got:

[4]:
plot

Plotting in 3D, 2D and 1D

The 3D view is great, but for big geometries it can take some time to render. If we have a 2d material, a 2D view might be more practical instead. We can get it by specifying the axes that we want:

[5]:
plot.update_settings(axes=[1,0])

In fact, we can use any arbitrary axis. The coordinates of the atoms will just get projected into them. Here we will use the direction [0,1,2] as our first axis and z as our second axis. Note that 0 is not equivalent to x, as 0 means “the first lattice vector”, which might be different from [1,0,0].

[6]:
plot.update_settings(axes=[[0,1,2], "z"])

In fact, this can be quite useful for “1d” representations. In this kind of representations, the first axis displays the coordinates (or projected coordinates) and the second one is at your disposal to do whatever you want. The values of the second axis are controlled by the dataaxis_1d setting.

It can be an array that explicitly sets the values:

[7]:
plot.update_settings(axes=[0], dataaxis_1d=plot.geometry.atoms.Z)

Or a function that accepts the projected coordinates and returns the values.

[8]:
plot.update_settings(dataaxis_1d=np.sin)

But let’s just go 2d for now :)

[9]:
plot = plot.update_settings(axes=[1,0])

Toggling bonds, atoms and cell

You might have noticed that, by default, the cell, atoms and bonds are displayed. Thanks to plotly’s capabilities, you can interactively toggle them by clicking at the names in the legend, which is great!

However, if you want to make sure they are not displayed in the first place, you can set the show_bonds, show_cell and show_atoms settings to False.

[10]:
plot.update_settings(show_cell=False, show_atoms=False)
---------------------------------------------------------------------------
IndexError                                Traceback (most recent call last)
<ipython-input-10-40bdd1ca65e3> in <module>
----> 1 plot.update_settings(show_cell=False, show_atoms=False)

/opt/gnu/9.3.0/python/packages/3.8.5/sisl-dev/0/lib/python3.8/site-packages/sisl-0.11.0.dev0-py3.8-linux-x86_64.egg/sisl/viz/plotly/configurable.py in update_settings(self, *args, **kwargs)
    422             # the available kwargs for the plot class and provide more help to the user
    423             def update_settings(self, *args, **kwargs):
--> 424                 return self._update_settings(*args, **kwargs)
    425
    426             update_settings.__doc__ = f"Updates the settings of this plot.\n\nDocs for {new_cls.__name__}:\n\n{get_configurable_docstring(new_cls)}"

/opt/gnu/9.3.0/python/packages/3.8.5/sisl-dev/0/lib/python3.8/site-packages/sisl-0.11.0.dev0-py3.8-linux-x86_64.egg/sisl/viz/plotly/configurable.py in _update_settings(self, run_updates, **kwargs)
    557             #Do things after updating the settings
    558             if len(self.settings_history.last_updated) > 0 and run_updates:
--> 559                 self._run_updates(self.settings_history.last_updated)
    560
    561         return self

/opt/gnu/9.3.0/python/packages/3.8.5/sisl-dev/0/lib/python3.8/site-packages/sisl-0.11.0.dev0-py3.8-linux-x86_64.egg/sisl/viz/plotly/configurable.py in _run_updates(self, for_keys)
    585         # Execute the functions that we need to execute.
    586         for f_name in func_names:
--> 587             getattr(self, f_name)()
    588
    589         return self

/opt/gnu/9.3.0/python/packages/3.8.5/sisl-dev/0/lib/python3.8/site-packages/sisl-0.11.0.dev0-py3.8-linux-x86_64.egg/sisl/viz/plotly/plotutils.py in apply_to_all_plots(obj, childs_sel, *args, **kwargs)
    820         else:
    821
--> 822             return method(obj, *args, **kwargs)
    823
    824     return apply_to_all_plots

/opt/gnu/9.3.0/python/packages/3.8.5/sisl-dev/0/lib/python3.8/site-packages/sisl-0.11.0.dev0-py3.8-linux-x86_64.egg/sisl/viz/plotly/configurable.py in func(obj, *args, **kwargs)
    884             def func(obj, *args, **kwargs):
    885                 getattr(obj, method_name)(**kwargs, **extra_kwargs)
--> 886                 return method(obj, *args, **kwargs)
    887
    888         elif when == 'after':

/opt/gnu/9.3.0/python/packages/3.8.5/sisl-dev/0/lib/python3.8/site-packages/sisl-0.11.0.dev0-py3.8-linux-x86_64.egg/sisl/viz/plotly/plot.py in set_data(self, update_fig, **kwargs)
   1129         self._starting_traces = len(self.data)
   1130
-> 1131         self._set_data()
   1132
   1133         if update_fig:

/opt/gnu/9.3.0/python/packages/3.8.5/sisl-dev/0/lib/python3.8/site-packages/sisl-0.11.0.dev0-py3.8-linux-x86_64.egg/sisl/viz/plotly/configurable.py in f_default_setting_args(self, *args, **kwargs)
    965                     pass
    966
--> 967         return f(self, *args, **kwargs)
    968
    969     return f_default_setting_args

/opt/gnu/9.3.0/python/packages/3.8.5/sisl-dev/0/lib/python3.8/site-packages/sisl-0.11.0.dev0-py3.8-linux-x86_64.egg/sisl/viz/plotly/plots/geometry.py in _set_data(self, axes, atoms, atoms_color, atoms_size, show_atoms, bind_bonds_to_ats, dataaxis_1d, kwargs3d, kwargs2d, kwargs1d)
    327         elif ndims == 2:
    328             xaxis, yaxis = axes
--> 329             self._plot_geom2D(xaxis=xaxis, yaxis=yaxis, **atoms_kwargs, bind_bonds_to_ats=bind_bonds_to_ats, **kwargs2d)
    330             self.update_layout(xaxis_title=f'Axis {xaxis} [Ang]', yaxis_title=f'Axis {yaxis} [Ang]')
    331         elif ndims == 1:

/opt/gnu/9.3.0/python/packages/3.8.5/sisl-dev/0/lib/python3.8/site-packages/sisl-0.11.0.dev0-py3.8-linux-x86_64.egg/sisl/viz/plotly/configurable.py in f_default_setting_args(self, *args, **kwargs)
    965                     pass
    966
--> 967         return f(self, *args, **kwargs)
    968
    969     return f_default_setting_args

/opt/gnu/9.3.0/python/packages/3.8.5/sisl-dev/0/lib/python3.8/site-packages/sisl-0.11.0.dev0-py3.8-linux-x86_64.egg/sisl/viz/plotly/plots/geometry.py in _plot_geom2D(self, xaxis, yaxis, atoms, atoms_color, atoms_size, atoms_colorscale, show_bonds, bind_bonds_to_ats, bonds_together, points_per_bond, show_cell, wrap_atoms, wrap_bond)
    657         self._display_props["atoms"]["colorscale"] = atoms_colorscale
    658
--> 659         xy = self._projected_2Dcoords(self.geometry[atoms], xaxis=xaxis, yaxis=yaxis)
    660         traces = []
    661

/opt/gnu/9.3.0/python/3.8.5/lib/python3.8/functools.py in _method(*args, **kwargs)
    910         def _method(*args, **kwargs):
    911             method = self.dispatcher.dispatch(args[0].__class__)
--> 912             return method.__get__(obj, cls)(*args, **kwargs)
    913
    914         _method.__isabstractmethod__ = self.__isabstractmethod__

/opt/gnu/9.3.0/python/packages/3.8.5/sisl-dev/0/lib/python3.8/site-packages/sisl-0.11.0.dev0-py3.8-linux-x86_64.egg/sisl/geometry.py in __getitem__(self, atoms)
    310     def __getitem__(self, atoms):
    311         """ Geometry coordinates (allows supercell indices) """
--> 312         return self.axyz(atoms)
    313
    314     @__getitem__.register(slice)

/opt/gnu/9.3.0/python/packages/3.8.5/sisl-dev/0/lib/python3.8/site-packages/sisl-0.11.0.dev0-py3.8-linux-x86_64.egg/sisl/geometry.py in axyz(self, atoms, isc)
   2738         if isc is None:
   2739             # get offsets from atomic indices (note that this will be per atom)
-> 2740             isc = self.a2isc(atoms)
   2741             offset = self.sc.offset(isc)
   2742             return self.xyz[self.sc2uc(atoms), :] + offset

/opt/gnu/9.3.0/python/packages/3.8.5/sisl-dev/0/lib/python3.8/site-packages/sisl-0.11.0.dev0-py3.8-linux-x86_64.egg/sisl/geometry.py in a2isc(self, atoms)
   3730         """
   3731         atoms = self._sanitize_atoms(atoms) // self.na
-> 3732         return self.sc.sc_off[atoms, :]
   3733
   3734     # This function is a bit weird, it returns a real array,

IndexError: arrays used as indices must be of integer (or boolean) type

Picking which atoms to display

The atoms setting of GeometryPlot allows you to pick which atoms to display. It accepts exactly the same possibilities as the atoms argument in Geometry’s methods.

Therefore, you can ask for certain indices:

[11]:
plot.update_settings(atoms=[1,2,3,4,5], show_atoms=True, show_cell="axes")
#show_cell accepts "box", "axes" and False

or use sisl categories to filter the atoms, for example.

We can use it to display only those atoms that have 3 neighbours:

[12]:
plot.update_settings(atoms={"neighbours": 3}, show_cell="box")

Notice that when we picked particular atoms, only the bonds of those atoms are displayed. You can change this by using the bind_bonds_to_ats setting.

[13]:
plot.update_settings(bind_bonds_to_ats=False)

In fact, when we set show_atoms to False, all that the plot does is to act as if atoms=[] and bind_bonds_to_ats=False.

Setting custom colors and size for atoms.

It is quite common that you have an atom-resolved property that you want to display. With GeometryPlot this is extremely easy :)

We can provide arrays for the atoms_color and atoms_size settings.

In the case of atoms_color we can provide the colors directly:

[14]:
# Let's color the atoms with orange and blue depending on their y position
colors = []
for x, y, z in plot.geometry.xyz:

    if y > 13:
        color = "orange"
    else:
        color = "blue"

    colors.append(color)


plot.update_settings(atoms_color=colors, atoms=None) # we set atoms to None to display all the atoms again

or provide an array of values that is mapped to colors using a color scale that you can, of course, change (atoms_colorscale setting).

[15]:
# Let's also color them using their y coordinate
y = plot.geometry.xyz[:,1]
plot.update_settings(atoms_color=y, atoms_colorscale="viridis")

Since “orange” size doesn’t make sense, the atoms_size array only accepts values.

[16]:
# We will determine their size using the x coordinate
x = plot.geometry.xyz[:, 0]

plot.update_settings(atoms_size=x*10) # we multiply it by 10 because otherwise the size is too small

Note that everything that we’ve done up to this moment is perfectly valid for the 3d view, we are just using the 2d view for convenience.

[17]:
plot.update_settings(axes=[0,1,2])

Guess why do we have a giant multicolor ball? :)

That’s right! Atom sizes are too big!

[18]:
plot.update_settings(atoms_size=x/4)

Much better!

We hope you enjoyed what you learned!


This next cell is just to create the thumbnail for the notebook in the docs

[19]:
thumbnail_plot = plot

if thumbnail_plot:
    thumbnail_plot.show("png")
../../../_images/visualization_plotly_showcase_GeometryPlot_41_0.png